package com.sleepcamel.exporter.test


import junit.framework.TestCase

import com.sleepcamel.exporter.DBExporter
import com.sleepcamel.exporter.model.category.StringCategory
import com.sleepcamel.exporter.persister.XMLPersister
import com.sleepcamel.exporter.util.JdbcUtils
import com.sleepcamel.rest.domain.BaseMethod
import com.sleepcamel.rest.domain.JavaClass
import com.sleepcamel.rest.domain.Mapping
import com.sleepcamel.rest.domain.Path
import com.sleepcamel.rest.domain.Project
import com.sleepcamel.rest.domain.ProjectPackage
import com.sleepcamel.rest.domain.method.RESTMethod
import com.sleepcamel.rest.domain.method.RESTMethodType
import com.sleepcamel.rest.domain.method.parameter.MethodParameter
import com.sleepcamel.rest.domain.method.parameter.RESTMethodParameter;
import com.sleepcamel.rest.domain.method.parameter.RESTMethodParameterType;
import com.sleepcamel.rest.domain.method.parameter.RESTMethodParameterTypeName;


class ProjectGenerationTest extends TestCase{

	static JdbcUtils jdbcUtils = new JdbcUtils(url:"jdbc:h2:file:/db-codeGen/testdb", userName:"sa", password:"", driver:"org.h2.Driver")
	XMLPersister persister = new XMLPersister()
	File dbDir
	DBExporter exporter 

	static String sqlDDL = '''
			DROP TABLE IF EXISTS EMPLOYEE, DEPARTMENT, ROLE, ROLE_EMPLOYEE;
			
			CREATE TABLE DEPARTMENT (
			  ID INTEGER AUTO_INCREMENT PRIMARY KEY,
			  name VARCHAR(30)
			);
			
			CREATE TABLE ROLE (
			    ROLE_ID INTEGER AUTO_INCREMENT PRIMARY KEY,
			    NAME VARCHAR(30)
			);
			
			CREATE TABLE EMPLOYEE (
			  EMP_ID INTEGER AUTO_INCREMENT PRIMARY KEY,
			  FK_DEPARTMENT_ID INTEGER NULL,
			  firstName VARCHAR(30),
			  LAST_NAME VARCHAR(30),
			  notNullVariable VARCHAR(30) not null,
			  matchingname VARCHAR(255),
			  FOREIGN KEY (FK_DEPARTMENT_ID) REFERENCES DEPARTMENT(ID)
			);
			
			
			CREATE TABLE ROLE_EMPLOYEE (
			    FK_ROLE_ID INTEGER,
			    FK_EMP_ID INTEGER,
			    
			    FOREIGN KEY (FK_ROLE_ID) REFERENCES ROLE(ROLE_ID),
			    FOREIGN KEY (FK_EMP_ID) REFERENCES EMPLOYEE(EMP_ID)
			);
			''';

	
	public void tearDown() {
		//dbDir.deleteDir();
	}
	
	public void setUp () {
		dbDir = new File("./db-codeGen")
		
		if(!dbDir.exists()){
			dbDir.mkdir()
		}
		
		dbDir.eachFile {File file ->
			file.delete()
		}
				
		jdbcUtils.executeScript(sqlDDL)
		persister.outputDir = dbDir
		
		exporter = new DBExporter()
		
		use(StringCategory) {
			exporter.jdbcUtils = jdbcUtils
			exporter.modelDirectory = dbDir
			exporter.generateModelFiles();

			assertNotNull(new File(persister.outputDir, "codeGen.xml").text)
		}
	}
	
	public void testStructure() {
		Project project = exporter.generateRESTProject();
		assertNotNull(project);

		ProjectPackage comPackage = project.getChilds().get(0);
		assertNotNull(comPackage);
		assertEquals(comPackage.getName(), "com");

		ProjectPackage sleepcamelPackage = comPackage.getChilds().get(0);
		assertNotNull(sleepcamelPackage);
		assertEquals(sleepcamelPackage.getName(), "sleepcamel");

		ProjectPackage examplePackage = sleepcamelPackage.getChilds().get(0);
		assertNotNull(examplePackage);
		assertEquals(examplePackage.getName(), "example");
	}
	
	private List<Mapping> getLastPackageMappings() {
		ProjectPackage examplePackage = exporter.generateRESTProject().getChilds().get(0).getChilds().get(0).getChilds().get(0);
		List<Mapping> mappings = examplePackage.getChilds();
		assertNotNull(mappings);
		Collections.sort(mappings, new Comparator<Mapping>(){
			int compare(Mapping arg0, Mapping arg1) {
				return arg0.getName().compareTo(arg1.getName());
			}
		});
		return mappings;
	}
	
	public void testMappings() {
		List<Mapping> mappings = getLastPackageMappings();
		assertEquals(mappings.size(), 3);
	}
	
	public void testDepartmentMapping() {
		List<Mapping> mappings = getLastPackageMappings();
		Mapping departmentMapping = mappings.get(0);
		assertEquals(departmentMapping.getName(), "DepartmentService");
		assertEquals(departmentMapping.getPath(), new Path("department"));
		assertEquals(16, departmentMapping.getChilds().size());
	}
	
	public void testRoleMapping() {
		List<Mapping> mappings = getLastPackageMappings();
		Mapping roleMapping = mappings.get(2);
		assertEquals(roleMapping.getName(), "RoleService");
		assertEquals(roleMapping.getPath(), new Path("role"));
		assertEquals(16, roleMapping.getChilds().size());
	}
	
	public void testEmployeeMapping() {
		List<Mapping> mappings = getLastPackageMappings();
		Mapping employeeMapping = mappings.get(1);
		assertEquals(employeeMapping.getName(), "EmployeeService");
		assertEquals(employeeMapping.getPath(), new Path("employee"));
		List<RESTMethod> methods = employeeMapping.getChilds();
		assertEquals(32, methods.size());
		
		Collections.sort(methods, new Comparator<BaseMethod>(){
			int compare(BaseMethod arg0, BaseMethod arg1) {
				return arg0.getName().compareTo(arg1.getName());
			}
		});
	}
	
	private RESTMethod getEmployeeMethod(String methodName) {
		List<Mapping> mappings = getLastPackageMappings();
		List<RESTMethod> methods = mappings.get(1).getChilds();
		for(RESTMethod method:methods){
			if ( method.getName().equals(methodName) )
				return method;
		}
		return null;
	}
	
	private JavaClass getGeneratedJavaClass(String className) {
		List<JavaClass> generatedJavaClass = exporter.getGeneratedJavaClasses();
		for(JavaClass javaClass:generatedJavaClass){
			if (javaClass.getName().equals(className))
				return javaClass;
		}
		return null;
	}

	public void testEmployeesGETMethod() {
		RESTMethod method = getEmployeeMethod("getEmployees");
		JavaClass employeeClass = getGeneratedJavaClass("Employee");
		
		assertNotNull(method);
		assertNotNull(employeeClass);
		
		assertTrue(method.getParameters().isEmpty());
		assertEquals(method.getPath(), new Path());
		assertEquals(method.getType(), RESTMethodType.GET);
		assertEquals(method.getReturnType(), employeeClass.asList());
	}
	
	public void testEmployeesPOSTMethod() {
		RESTMethod method = getEmployeeMethod("postEmployees");
		JavaClass employeeClass = getGeneratedJavaClass("Employee");
		
		assertNotNull(method);
		assertNotNull(employeeClass);
		
		List<MethodParameter> parameters = method.getParameters();
		assertEquals(1,method.getParameters().size());
		
		MethodParameter listParameter = parameters.get(0);
		assertEquals(listParameter.getName(), "employees");
		assertEquals(listParameter.getType(), employeeClass.asList());
		assertEquals(listParameter.getClass(), MethodParameter.class);

		assertEquals(method.getPath(), new Path());
		assertEquals(method.getType(), RESTMethodType.POST);
		assertEquals(method.getReturnType(), JavaClass.voidClass);
	}
	
	public void testEmployeesPUTMethod() {
		RESTMethod method = getEmployeeMethod("putEmployees");
		JavaClass employeeClass = getGeneratedJavaClass("Employee");
		
		assertNotNull(method);
		assertNotNull(employeeClass);
		
		List<MethodParameter> parameters = method.getParameters();
		assertEquals(1,method.getParameters().size());
		
		MethodParameter listParameter = parameters.get(0);
		assertEquals(listParameter.getName(), "employees");
		assertEquals(listParameter.getType(), employeeClass.asList());
		assertEquals(listParameter.getClass(), MethodParameter.class);
		
		assertEquals(method.getPath(), new Path());
		assertEquals(method.getType(), RESTMethodType.PUT);
		assertEquals(method.getReturnType(), JavaClass.voidClass);
	}
	
	public void testEmployeesDELETEMethod() {
		RESTMethod method = getEmployeeMethod("deleteEmployees");
		JavaClass employeeClass = getGeneratedJavaClass("Employee");
		
		assertNotNull(method);
		assertNotNull(employeeClass);
		
		assertTrue(method.getParameters().isEmpty());
		assertEquals(method.getPath(), new Path());
		assertEquals(method.getType(), RESTMethodType.DELETE);
		assertEquals(method.getReturnType(), JavaClass.voidClass);
	}
	
	public void testEmployeeGETMethod() {
		RESTMethod method = getEmployeeMethod("getEmployee");
		JavaClass employeeClass = getGeneratedJavaClass("Employee");
		
		assertNotNull(method);
		assertNotNull(employeeClass);
		
		List<MethodParameter> parameters = method.getParameters();
		assertEquals(1,method.getParameters().size());

		RESTMethodParameter idParameter = parameters.get(0);
		assertEquals(idParameter.getName(), "id");
		assertEquals(idParameter.getType(), employeeClass.getId().getJavaClass());
		
		RESTMethodParameterType restMethodParameterType = idParameter.getRestParameterType();
		assertEquals(restMethodParameterType.getName(), RESTMethodParameterTypeName.PathParam);
		assertEquals(restMethodParameterType.getValue(), "id");
		
		assertEquals(method.getPath(), new Path("{id}"));
		assertEquals(method.getType(), RESTMethodType.GET);
		assertEquals(method.getReturnType(), employeeClass);
	}
	
	public void testEmployeePOSTMethod() {
		RESTMethod method = getEmployeeMethod("postEmployee");
		JavaClass employeeClass = getGeneratedJavaClass("Employee");
		
		assertNotNull(method);
		assertNotNull(employeeClass);
		
		List<MethodParameter> parameters = method.getParameters();
		assertEquals(2,method.getParameters().size());

		RESTMethodParameter idParameter = parameters.get(0);
		assertEquals(idParameter.getName(), "id");
		assertEquals(idParameter.getType(), employeeClass.getId().getJavaClass());
		
		RESTMethodParameterType restMethodParameterType = idParameter.getRestParameterType();
		assertEquals(restMethodParameterType.getName(), RESTMethodParameterTypeName.PathParam);
		assertEquals(restMethodParameterType.getValue(), "id");
		
		MethodParameter entityParameter = parameters.get(1);
		assertEquals(entityParameter.getName(), "employee");
		assertEquals(entityParameter.getType(), employeeClass);
		assertEquals(entityParameter.getClass, MethodParameter.class);
		
		assertEquals(method.getPath(), new Path("{id}"));
		assertEquals(method.getType(), RESTMethodType.POST);
		assertEquals(method.getReturnType(), JavaClass.voidClass);
	}
	
	public void testEmployeePUTMethod() {
		RESTMethod method = getEmployeeMethod("putEmployee");
		JavaClass employeeClass = getGeneratedJavaClass("Employee");
		
		assertNotNull(method);
		assertNotNull(employeeClass);
		
		List<MethodParameter> parameters = method.getParameters();
		assertEquals(2,method.getParameters().size());

		RESTMethodParameter idParameter = parameters.get(0);
		assertEquals(idParameter.getName(), "id");
		assertEquals(idParameter.getType(), employeeClass.getId().getJavaClass());
		
		RESTMethodParameterType restMethodParameterType = idParameter.getRestParameterType();
		assertEquals(restMethodParameterType.getName(), RESTMethodParameterTypeName.PathParam);
		assertEquals(restMethodParameterType.getValue(), "id");
		
		MethodParameter entityParameter = parameters.get(1);
		assertEquals(entityParameter.getName(), "employee");
		assertEquals(entityParameter.getType(), employeeClass);
		assertEquals(entityParameter.getClass, MethodParameter.class);
		
		assertEquals(method.getPath(), new Path("{id}"));
		assertEquals(method.getType(), RESTMethodType.PUT);
		assertEquals(method.getReturnType(), JavaClass.voidClass);
	}
	
	public void testEmployeeDELETEMethod() {
		RESTMethod method = getEmployeeMethod("deleteEmployee");
		JavaClass employeeClass = getGeneratedJavaClass("Employee");
		
		assertNotNull(method);
		assertNotNull(employeeClass);
		
		List<MethodParameter> parameters = method.getParameters();
		assertEquals(1,method.getParameters().size());

		RESTMethodParameter idParameter = parameters.get(0);
		assertEquals(idParameter.getName(), "id");
		assertEquals(idParameter.getType(), employeeClass.getId().getJavaClass());
		
		RESTMethodParameterType restMethodParameterType = idParameter.getRestParameterType();
		assertEquals(restMethodParameterType.getName(), RESTMethodParameterTypeName.PathParam);
		assertEquals(restMethodParameterType.getValue(), "id");
		
		assertEquals(method.getPath(), new Path("{id}"));
		assertEquals(method.getType(), RESTMethodType.DELETE);
		assertEquals(method.getReturnType(), JavaClass.voidClass);
	}
	
	public void testEmployeeDepartmentGETMethod() {
		RESTMethod method = getEmployeeMethod("getDepartmentField");
		JavaClass employeeClass = getGeneratedJavaClass("Employee");
		
		assertNotNull(method);
		assertNotNull(employeeClass);
		
		List<MethodParameter> parameters = method.getParameters();
		assertEquals(1,method.getParameters().size());
		
		RESTMethodParameter idParameter = parameters.get(0);
		assertEquals(idParameter.getName(), "id");
		assertEquals(idParameter.getType(), employeeClass.getId().getJavaClass());
		
		RESTMethodParameterType restMethodParameterType = idParameter.getRestParameterType();
		assertEquals(restMethodParameterType.getName(), RESTMethodParameterTypeName.PathParam);
		assertEquals(restMethodParameterType.getValue(), "id");
		
		assertEquals(method.getPath(), new Path("{id}/department"));
		assertEquals(method.getType(), RESTMethodType.GET);
		assertEquals(method.getReturnType(), employeeClass.getPropertyByName("department").getJavaClass());
	}
	
	public void testEmployeeDepartmentPOSTMethod() {
		RESTMethod method = getEmployeeMethod("postDepartmentField");
		JavaClass employeeClass = getGeneratedJavaClass("Employee");
		
		assertNotNull(method);
		assertNotNull(employeeClass);
		
		List<MethodParameter> parameters = method.getParameters();
		assertEquals(2,method.getParameters().size());
		
		RESTMethodParameter idParameter = parameters.get(0);
		assertEquals(idParameter.getName(), "id");
		assertEquals(idParameter.getType(), employeeClass.getId().getJavaClass());
		
		RESTMethodParameterType restMethodParameterType = idParameter.getRestParameterType();
		assertEquals(restMethodParameterType.getName(), RESTMethodParameterTypeName.PathParam);
		assertEquals(restMethodParameterType.getValue(), "id");
		
		MethodParameter entityParameter = parameters.get(1);
		assertEquals(entityParameter.getName(), "department");
		assertEquals(entityParameter.getType(), employeeClass.getPropertyByName("department").getJavaClass());
		assertEquals(entityParameter.getClass, MethodParameter.class);
		
		assertEquals(method.getPath(), new Path("{id}/department"));
		assertEquals(method.getType(), RESTMethodType.POST);
		assertEquals(method.getReturnType(), JavaClass.voidClass);
	}
	
	public void testEmployeeDepartmentPUTMethod() {
		RESTMethod method = getEmployeeMethod("putDepartmentField");
		JavaClass employeeClass = getGeneratedJavaClass("Employee");
		
		assertNotNull(method);
		assertNotNull(employeeClass);
		
		List<MethodParameter> parameters = method.getParameters();
		assertEquals(2,method.getParameters().size());
		
		RESTMethodParameter idParameter = parameters.get(0);
		assertEquals(idParameter.getName(), "id");
		assertEquals(idParameter.getType(), employeeClass.getId().getJavaClass());
		
		RESTMethodParameterType restMethodParameterType = idParameter.getRestParameterType();
		assertEquals(restMethodParameterType.getName(), RESTMethodParameterTypeName.PathParam);
		assertEquals(restMethodParameterType.getValue(), "id");
		
		MethodParameter entityParameter = parameters.get(1);
		assertEquals(entityParameter.getName(), "department");
		assertEquals(entityParameter.getType(), employeeClass.getPropertyByName("department").getJavaClass());
		assertEquals(entityParameter.getClass, MethodParameter.class);
		
		assertEquals(method.getPath(), new Path("{id}/department"));
		assertEquals(method.getType(), RESTMethodType.PUT);
		assertEquals(method.getReturnType(), JavaClass.voidClass);
	}
	
	public void testEmployeeDepartmentDELETEMethod() {
		RESTMethod method = getEmployeeMethod("deleteDepartmentField");
		JavaClass employeeClass = getGeneratedJavaClass("Employee");
		
		assertNotNull(method);
		assertNotNull(employeeClass);
		
		List<MethodParameter> parameters = method.getParameters();
		assertEquals(1,method.getParameters().size());
		
		RESTMethodParameter idParameter = parameters.get(0);
		assertEquals(idParameter.getName(), "id");
		assertEquals(idParameter.getType(), employeeClass.getId().getJavaClass());
		
		RESTMethodParameterType restMethodParameterType = idParameter.getRestParameterType();
		assertEquals(restMethodParameterType.getName(), RESTMethodParameterTypeName.PathParam);
		assertEquals(restMethodParameterType.getValue(), "id");
		
		assertEquals(method.getPath(), new Path("{id}/department"));
		assertEquals(method.getType(), RESTMethodType.DELETE);
		assertEquals(method.getReturnType(), JavaClass.voidClass);
	}
	
}